#pragma once

#include "vec3.h"

OPEN_JLIB_NS


struct Box3 {

  Vec3 min, max;

  inline Box3 () noexcept = default;
  inline Box3 (f32 minx, f32 miny, f32 minz, f32 maxx, f32 maxy, f32 maxz) noexcept : min(minx, miny, minz), max(maxx, maxy, maxz) {
  }
  inline Box3 (Vec3 min, Vec3 max) noexcept : min(min), max(max) {
  }
  inline Box3 (const f32 *m) noexcept : min(m), max(m+3) {
  }


  inline Box3& operator&= (Box3 v) noexcept {
    min = Vec3::max(min, v.min);
    max = Vec3::min(max, v.max);
    return *this;
  }
  inline Box3& operator|= (Box3 v) noexcept {
    min = Vec3::min(min, v.min);
    max = Vec3::max(max, v.max);
    return *this;
  }


  inline Box3 operator& (Box3 v) const noexcept {
    return {
      Vec3::max(min, v.min),
      Vec3::min(max, v.max),
    };
  }
  inline Box3 operator| (Box3 v) const noexcept {
    return {
      Vec3::min(min, v.min),
      Vec3::max(max, v.max),
    };
  }


  inline Vec3 operator~ () const noexcept {
    return max - min;
  }


  inline f32 x () const noexcept {
    return min.x();
  }
  inline f32 y () const noexcept {
    return min.y();
  }
  inline f32 z () const noexcept {
    return min.z();
  }
  inline f32 X () const noexcept {
    return max.x();
  }
  inline f32 Y () const noexcept {
    return max.y();
  }
  inline f32 Z () const noexcept {
    return max.z();
  }


  inline Vec3 xyz () const noexcept {
    return min;
  }
  inline Vec3 xyZ () const noexcept {
    return {min.p[0], min.p[1], max.p[2]};
  }
  inline Vec3 xYz () const noexcept {
    return {min.p[0], max.p[1], min.p[2]};
  }
  inline Vec3 xYZ () const noexcept {
    return {min.p[0], max.p[1], max.p[2]};
  }
  inline Vec3 Xyz () const noexcept {
    return {max.p[0], min.p[1], min.p[2]};
  }
  inline Vec3 XyZ () const noexcept {
    return {max.p[0], min.p[1], max.p[2]};
  }
  inline Vec3 XYz () const noexcept {
    return {max.p[0], max.p[1], min.p[2]};
  }
  inline Vec3 XYZ () const noexcept {
    return max;
  }


  inline bool contains (Vec3 v) const noexcept {
    return min.p[0] <= v.p[0]
    && min.p[1] <= v.p[1]
    && min.p[2] <= v.p[2]
    && max.p[0] >= v.p[0]
    && max.p[1] >= v.p[1]
    && max.p[2] >= v.p[2];
  }
  inline bool contains (Box3 v) const noexcept {
    return min.p[0] <= v.min.p[0]
    && min.p[1] <= v.min.p[1]
    && min.p[2] <= v.min.p[2]
    && max.p[0] >= v.max.p[0]
    && max.p[1] >= v.max.p[1]
    && max.p[2] >= v.max.p[2];
  }
  inline bool intersect (Box3 v) const noexcept {
    return min.p[0] < v.max.p[0]
    && min.p[1] < v.max.p[1]
    && min.p[2] < v.max.p[2]
    && max.p[0] > v.min.p[0]
    && max.p[1] > v.max.p[1]
    && max.p[2] > v.max.p[2];
  }
};


CLOSE_JLIB_NS